// 迭代器的出现是为了解决【复杂】性循环中对于跟踪变量错误引用以及以及其他BUG

// colors = ['red', 'yellow', 'blue']
// for(var i = 0; i < colors.length; i++ ) {
//   console.log(colors[i])
// }

// ----------------------------
// 1. 什么是迭代器
// 一种特殊的对象，存在专门为迭代器设计的接口
// 具备 next() 方法，触发执行一次的迭代，并返回一个对象
// 返回的对象有两个属性 
//  value ，表示下一次执行的结果
//  done，判断是否可以继续执行，为true是

// 补充：iterator 读音 -> [ɪtə'retɚ]

// ES5实现迭代器
// function createIterator(items) {
//   let index = 0

//   return {
//     next() {
//       return {
//         value: items[index++],
//         done: !(index < items.length)
//       }
//     }
//   }
// }

// let iterator = createIterator([1, 2, 3])
// console.log(iterator)
// console.log(iterator.next()) // { value: 1, done: false }
// console.log(iterator.next()) // { value: 2, done: false }
// console.log(iterator.next()) // { value: 3, done: true }
// console.log(iterator.next()) // { value: undefined, done: true }
// console.log(iterator.next()) // { value: undefined, done: true }

// ------------------------------------------- 
// 2. 什么是生成器
// 就是一种返回迭代器对象的函数
// 生成器函数在 function 关键字后加【*】（中间可以有空格）
// 函数内存在 yield 关键字，函数执行到该语句会停止执行
// （等待迭代器对象再次调用 next 后执行）
// 函数最终返回一个迭代器对象
// 注意：yield 关键字只能在市场器中出现，类似于return语句不能穿透函数体

// function * createIterator() {
//   yield 1;
//   yield 2;
//   yield 3
// }

// let iterator = createIterator()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// -------------------------------------
// function* createIterator(items) {
//   for(let i = 0; i < items.length; i++) {
//     yield items[i]
//   }
// }

// let iterator = createIterator([1, 2, 3])
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// -------------------------------------
// 生成函数表达式
// 注意：不能用箭头函数
// const createIterator = function* (items) {
//   for (let i = 0; i < items.length; i++) {
//     yield items[i]
//   }
// }

// let iterator = createIterator(['a', 'b', 'c'])
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// -------------------------------------
// 生成器对象的方法
// 1. 用函数表达式
// 2. ES6的简写，函数前加【*】
// let obj = {
//   iterator: function *() {
//     yield 1;
//     yield 2;
//   },
//   *iterator_2() {
//     yield 'c',
//     yield 'd'
//   }
// }
// const obj_iter = obj.iterator()
// console.log(obj.iterator().next())
// console.log(obj.iterator().next())
// console.log(obj_iter.next())
// console.log(obj_iter.next())

// -------------------------------------
// 可迭代对象（例如Map、Set、数组、字符串）
// 都具备 Symbol.iterator 属性，作为默认迭代器
// 
// for...of 
// 每次执行都会调用可迭代对象的next() 方法，
// 将返回对象的value储存在变量中，直到 done 为true
// let arr = [1, 2, 3]
// const iterator = arr[Symbol.iterator]()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// -------------------------------------
// 创建可迭代对象
// 默认开发者创建的对象都是不可迭代的，可以手动给Symbol.iterator 属性添加生成器
// let obj = {
//   list: [],
//   *[Symbol.iterator]() {
//     for(let value of this.list) {
//       yield value
//     }
//   }
// }

// obj.list = [1, 2, 3]
// for(let val of obj) {
//   console.log(val)
// }

// -------------------------------------
// 遍历对象属性的5种方式
/**
 * 1. for...in 对象中可枚举的属性（包括继承来的属性）
 * 2. Object.getOwnPropertyNames 对象自身属性（无论是否可枚举）
 * 3. Object.entries()、Object.keys()、Object.values() 数组，和 for...in 类似但是在返回自身属性
 * 4. for...of 遍历可迭代对象（[Symbol.iterator]属性）
 * 5. Reflect.ownKeys() 返回对象自身属性（包括 Symbol 属性） =》 getOwnProperty + getOwnPropertySymbols
 */

// let obj = {
//   name: 'wgf',
//   age: 20,
//   *[Symbol.iterator]() {
//     const prototypes = Object.getOwnPropertyNames(this)
//     for(let i = 0; i < prototypes.length; i++) {
//       yield this[prototypes[i]]
//     }
//   }
// }

// obj.__proto__.prototype = {
//   a: 1,
//   b: 2
// }


// for(const key of obj) {
//   console.log(key)
// }
// console.log(obj)

// ------------------------------------
// 内建迭代器

// 集合：数组、Map对象、Set对象
// 1. entries()
// 2. keys()
// 3. values()

// const arr = [1, 2, 3]

// console.log(arr.entries())
// console.log(arr.keys())
// console.log(arr.values())

// 默认迭代器
// 每种集合数据类型都有，在 for...of 语句默认调用
// 数组 和 Set 是 values()
// Map 是 entries

// const set = new Set([1, 2, 3])

// for(const value of set) {
//   console.log(value)
// }

// ----------------------------------
// 字符串迭代器
// ES5 后字符串越来越像数组（中括号访问、length）

// let test = 'A与B'
// for(let i = 0; i < test.length; i ++) {
//   console.log(test[i])
// }

// ---------------------------------
// NodeList 迭代器

// let divs = document.getElementsByTagName('div')

// for(let div of devs) {
//   console.log(div.id)
// }

// ------------------------------
// 展开运算符与非数组可迭代对象
// 会调用该对象的【默认迭代器】进行展开运算

// let map = new Map([[1, 2], [2, 3]])
// map.set('name', 'wgf')
// let arr = [...map]

// console.log(map)
// console.log(arr)

// ----------------------------
// 高级迭代器功能

// 1. 给迭代器传递参数
// 给 迭代器的 next() 传递值 =》 会替代 yield 的返回值

// function * createIterator() {
//   let first = yield 1;
//   console.log('n-', first)
//   let second = yield first + 2;
//   yield second + 4;
// }

// const iterator = createIterator()
// console.log(iterator.next())
// console.log(iterator.next(2))
// console.log(iterator.next(4))

// 第一次的next无论什么传什么值，都不会有意义的
// 第二次 next 后， yield 的右侧为 next 的返回值，而左侧将获得第二次next() 所传递的参数

// --------------------------
// 2. 迭代器中抛出错误
// 可以通过 throw 在迭代器中抛出错误

// function * createIterator() {
//   let first = yield 1;
//   console.log('n-', first)
//   let second = yield first + 2;
//   yield second + 4;
// }

// const iterator = createIterator()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.throw(new Error('BOOM')))

// 就可以在生成器中 try...catch 进行处理\
// 有趣的现象：由于错误在迭代器内部捕获，throw()执行结果和next()类似
// 继续执行，并返回 yield 右侧结果

// function * createIterator() {
//   let first = yield 1;
//   let second;

//   try {
//     second = yield first + 2;
//   } catch (error) {
//     console.log(error)
//     second = 6
//   }

//   yield second = second + 3
// }

// const iterator = createIterator()

// console.log(iterator.next())
// console.log(iterator.next(4))
// console.log(iterator.throw(new Error('BOOM')))
// console.log(iterator.next())

// ---------------------------------
// 3。 生成器的返回语句
// 生成器本质还是一个函数，所以return依然会终止函数
// 返回 return 的结果，并且 done 会设置为 true

// function * createIterator () {
//   yield 1;
//   return 'over';
//   yield 2;
//   yield 3;
// }

// const iterator = createIterator()

// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// 注意：for...of 和 展开运算符 会忽略 return 的结果，在 done 值为 true后终止

// ----------------------------------
// 4. 委托生成器
// 应用场景：合并生成器
// 在生成器的内部 yield *【生成器】即可

// function * createIteratorNum() {
//   yield 1;
//   yield 2;
// }

// function * createIteratorColor() {
//   yield 'red';
//   yield 'yellow';
// }

// function * createIterator () {
//   yield * createIteratorNum()
//   yield * createIteratorColor()
// }

// const iterator = createIterator()

// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// ------------------------------------
// 在委托生成器中应用返回语句

// function * createIteratorNum() {
//   yield 1;
//   yield 2;
//   return 3;
// }

// function * getValue() {
//   let result = yield *createIteratorNum()
//   // 注意： return后将继续执行，所以迭代器中不会出现{ value: 3, done: false}的返回中
//   for(let i = 0; i < result; i++) {
//     yield 'repeat'
//   }
// }

// const iterator = getValue()

// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())

// 而器 yield *也可以用于字符串，调用其默认迭代器

// --------------------------------
// 异步任务执行

// ----------- 读取文件 -------------
// let fs = require("fs");

// fs.readFile("test.txt", function (error, content) {
//   if(error) {
//     throw new Error(error)
//   }

//   doSomeThing(content)
//   console.log("Done")
// })

// 少量任务，这样做很好
// 但是存在嵌套逻辑或者系列化一系列的异步操作
// ---------------------------------
// 简单的任务执行器

// function run(taskDef) {
//   // 创建无使用限制的迭代器
//   let task = taskDef()

//   // 开始执行任务
//   let result = task.next()

//   // 循环调用 next() 函数
//  function step() {
//    // 任务未完成继续执行下一步
//     if(!result.done) {
//       result = task.next()
//       step()
//     }
//   }

//   step()
// }

// run(function *login() {
//   console.log("get UserName And Password")
//   yield;
//   console.log("get this user Auth")
//   yield;
//   console.log('Login')
// })

// -------------------------------------
// 任务执行器的数据传递
// function run(taskDef) {
//   let task = taskDef()

//   let result = task.next()

//  function step() {
//     if(!result.done) {
//       result = task.next(result.value)
//       step()
//     }
//   }

//   step()
// }

// run(function *() {
//   let res = yield 1;
//   console.log(res);
//   res = yield res + 3;
//   console.log(res);
// })

// --------------------------------
// 异步任务执行器

function fetchData() {
  return function (callback) {
    setTimeout(function () {
      callback(null, 'Hi')
    }, 50)
  }
}

function run(taskDef) {
  let task = taskDef()

  let result = task.next()

  function step() {
    // 首先判断任务是否完成
    if(!result.done) {
      if(result.value instanceof Function) {
        result.value(function(err, data) {
          if(err) {
            result = task.throw(err)
            return;
          }

          result = task.next(data)
          step()
        })
      } else {
        result = task.next(result.value)
        step()
      }
    }
  }

  step();
}

run(function *() {
  let str = yield 'HEllo'
  console.log(str)

  str += yield fetchData()
  console.log(str)

  str += yield 'laster_3'
  console.log(str)
})

// ---------------------------------

let fs = require('fs')

function readFile(fileName) {
  return function (callback) {
    fs.read(fileName, callback)
  }
}

run(function *() {
  let content = yield readFile('config.json')
  doSomeThing(content)
  console.log('Done')
})





